package mobcounter;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;

public class MapPaintWidget extends JPanel
        implements MouseListener, MouseMotionListener {

    private Color currentColor = Color.BLACK;
    int brushSize = 1;
    private boolean dragging;
    BufferedImage biMap = null;
    BufferedImage biDrawing = null;
    BufferedImage biBrushPreview = null;
    int mx, my;
    Graphics2D gDrawing;
    Font stdFont;

    public interface IPaintUpdate {
        void PaintUpdate(MapPaintWidget widget);
        void EndPaint( MapPaintWidget widget);
    }
    public IPaintUpdate paintUpdate;

    MapPaintWidget() {
        setBackground(Color.WHITE);
        addMouseListener(this);
        addMouseMotionListener(this);
        stdFont = new Font("TimesRoman", Font.PLAIN, 20);
        SetBrushSize(200);

    }

    public float Cal(float pixelPerPerson) {

        if( biDrawing == null)
            return 0;
        
        float sum = 0.0f;

        for (int x = 0; x < biDrawing.getWidth(); x++) {
            for (int y = 0; y < biDrawing.getHeight(); y++) {
                int color = biDrawing.getRGB(x, y);
                int alpha = (color >> 24) & 0xff;
                if (alpha > 0) {
                    sum += (pixelPerPerson);
                }
            }
        }

        return sum;

    }

    public void SetBrushSize(int size) {
        if (biBrushPreview == null
                || biBrushPreview.getWidth() < size
                || biBrushPreview == null) {
            biBrushPreview = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
        }

        brushSize = size;
        Graphics2D drawer = (Graphics2D) biBrushPreview.createGraphics();
        drawer.setColor(new Color(0, 0, 0, 0));
        drawer.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
        drawer.fillRect(0, 0, biBrushPreview.getWidth(), biBrushPreview.getHeight());
        drawer.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
        drawer.setColor(new Color(1f, 1f, 0f, 1.0f));
        drawCircle(drawer, biBrushPreview.getWidth() / 2, biBrushPreview.getHeight() / 2, size);
        repaint();
    }
    
    public void Clear(){
        if (biDrawing != null) {
            Graphics2D tgDrawing = (Graphics2D)biDrawing.getGraphics();
            tgDrawing.setColor(new Color(0, 0, 0, 0));
            tgDrawing.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
            tgDrawing.fillRect(0, 0, biDrawing.getWidth(), biDrawing.getHeight());
        }
        repaint();
    }

    public void SetImage(BufferedImage image) {
        this.biMap = image;

        biDrawing = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);

        currentColor = new Color(1f, 0f, 0f, 1.0f);
        gDrawing = (Graphics2D) biDrawing.createGraphics();
        gDrawing.setColor(new Color(1f, 0f, 0f, 1.0f));

        repaint();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        if (biMap != null) {
            g.drawImage(biMap, 0, 0, this);
        }

        if (biDrawing != null) {
            g.drawImage(biDrawing, 0, 0, this);
        }

        if (biBrushPreview != null) {
            g.drawImage(biBrushPreview, mx - (biBrushPreview.getWidth() / 2), my - (biBrushPreview.getHeight() / 2), this);
        }

    }

    public void SetPaintMode(Color color) {
        if (gDrawing != null) {
            currentColor = color;
            gDrawing.setColor(currentColor);
            gDrawing.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
        }
    }

    public void SetEreaseMode() {
        if (gDrawing != null) {
            gDrawing.setColor(new Color(0, 0, 0, 0));
            gDrawing.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
        }
    }
    
    public BufferedImage GetImage( float pixelPerPerson ){
        
        BufferedImage tmp = new BufferedImage( 
                biMap.getWidth()
                , biMap.getHeight()
                , BufferedImage.TYPE_INT_ARGB_PRE);

        Graphics2D gtmp = (Graphics2D) tmp.createGraphics();
        gtmp.drawImage( biMap, null, this);
        gtmp.drawImage( biDrawing, null, this);
        
        gtmp.setFont(stdFont); 
        gtmp.setColor(Color.BLACK);
        float person = Cal(pixelPerPerson);
        gtmp.drawString( "1Pixel ต่อ " + pixelPerPerson + " : จำนวนคนโดยประมาณ " + person, 21, 21);
        gtmp.setColor(Color.WHITE);
        gtmp.drawString( "1Pixel ต่อ " + pixelPerPerson + " : จำนวนคนโดยประมาณ " + person, 20, 20);
        
        return tmp;
    }

    @Override
    public void mousePressed(MouseEvent evt) {
        if (dragging == true) {
            return;
        }
        dragging = true;
        if (gDrawing != null) {
            fillCircle(gDrawing, evt.getX(), evt.getY(), brushSize);
        }

        emitEventPaintUpdate();

        mx = evt.getX();
        my = evt.getY();

        repaint();
    }

    @Override
    public void mouseReleased(MouseEvent evt) {
        if (dragging == false) {
            return;
        }
        emitEventEndPaint();
        dragging = false;
    }

    @Override
    public void mouseDragged(MouseEvent evt) {
        if (dragging == false) {
            return;
        }
        if (gDrawing != null) {
            fillCircle(gDrawing, evt.getX(), evt.getY(), brushSize);
        }

        emitEventPaintUpdate();

        mx = evt.getX();
        my = evt.getY();

        repaint();
    }

    public void fillCircle(Graphics g, int cx, int cy, int r) {
        g.fillOval(cx - r, cy - r, 2 * r, 2 * r);
    }

    public void drawCircle(Graphics g, int cx, int cy, int r) {
        g.drawOval(cx - r, cy - r, 2 * r, 2 * r);
    }
    
    public boolean isReady()
    {
        boolean isready = 
                biBrushPreview != null
                && biDrawing != null
                && biMap != null;
        return isready;
    }
    
    void emitEventEndPaint()
    {
        if( paintUpdate != null )
            paintUpdate.EndPaint(this);
    }
    
    void emitEventPaintUpdate()
    {
        if( paintUpdate != null )
            paintUpdate.PaintUpdate(this);
    }

    @Override
    public void mouseEntered(MouseEvent evt) {
        mx = evt.getX();
        my = evt.getY();
        repaint();
    }

    @Override
    public void mouseExited(MouseEvent evt) {
        mx = biBrushPreview.getWidth() / 2;
        my = biBrushPreview.getHeight() / 2;
        emitEventEndPaint();
        repaint();
    }

    @Override
    public void mouseClicked(MouseEvent evt) {
    }

    @Override
    public void mouseMoved(MouseEvent evt) {
        mx = evt.getX();
        my = evt.getY();
        repaint();
    }
}
